
`include "common_header.verilog"

//  *************************************************************************
//  File : register_map_pcs_chnl.vhd
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2008 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Thomas Schrobenhauser, Denis Poverennyy
//  info@morethanip.com
//  *************************************************************************
//  Description : Registers for 40G PCS
//  Version     : $Id: register_map_pcs_40g.v,v 1.6 2013/03/12 23:30:45 dk Exp $
//  *************************************************************************

module register_map_pcs_40g (

   reset_rx_clk,
   reset_tx_clk,
   reset_reg_clk,
   rx_clk,
   tx_clk,
   reg_clk,
   rx_err,
   tx_err,
   link_status,
   lane_map,
   block_lock,
   block_lock_3_0,
   align_lock,
   align_lock_3_0,
   hi_ber,
   ber_count,
   err_block_cnt,
   pat_err_cnt,
   bip8_stat_0,
   bip8_stat_1,
   bip8_stat_2,
   bip8_stat_3,
   ber_count_read,
   err_block_cnt_rd,
   tx_test_mode,
   rx_test_mode,
   pat_err_cnt_rd,

`ifdef MTIPPCS82_EEE_ENA 
        
   lpi_fw,
   tx_lpi_indication,
   rx_lpi_indication,
   wake_error_counter,
   wake_error_counter_rd,

`endif

`ifdef MTIP_DIR_CONFIG
   sw_reset_dir,
`endif
   reg_rd,
   reg_wr,
   reg_addr,
   reg_din,
   reg_dout,
   reg_busy,
   sw_reset,
   loopback_ena
`ifdef MTIPPCS40_VENDORCFGREGS
   ,
   vl_intvl,
   tx_lane_thresh
`endif
   );

parameter CHNL_NO = 4'b 0000;

`include "mtip_pcs100g_pack_package.verilog"

input   reset_rx_clk;                   //  Asynchronous Reset - rx_clk Domain
input   reset_tx_clk;                   //  Asynchronous Reset - tx_clk Domain
input   reset_reg_clk;                  //  Asynchronous Reset - reg_clk Domain
input   rx_clk;                         //  312.5MHz XL/CGMII Receive Clock
input   tx_clk;                         //  312.5MHz XL/CGMII Transmit Clock
input   reg_clk;                        //  Reference Interface Clock
input   rx_err;                         //  Error on receive path
input   tx_err;                         //  Error on transmit path
input   link_status;                    //  Link status on receive path
input   [7:0] lane_map;                 //  Lane mapping status - 2 bit per lane
input   block_lock;                     //  Block lock state reached
input   [3:0] block_lock_3_0;           //  Block lock state reached per lane
input   align_lock;                     //  Alignment marker lock state reached
input   [3:0] align_lock_3_0;           //  Alignment marker lock state reached per VL
input   hi_ber;                         //  High Bit Error
input   [21:0] ber_count;               //  BER_count counter to be read
input   [21:0] err_block_cnt;           //  Block error counter to be read
input   [15:0] pat_err_cnt;             //  Receive test pattern error counter
input   bip8_stat_0;                    //  BIP-8 error status lane 0
input   bip8_stat_1;                    //  BIP-8 error status lane 1
input   bip8_stat_2;                    //  BIP-8 error status lane 2
input   bip8_stat_3;                    //  BIP-8 error status lane 3
output  ber_count_read;                 //  BER_count counters have been read
output  err_block_cnt_rd;               //  Block error counter has been read
output  tx_test_mode;                   //  Transmit test pattern mode
output  rx_test_mode;                   //  Receive test pattern mode
output  pat_err_cnt_rd;                 //  Receive test pattern error counter has been read

`ifdef MTIPPCS82_EEE_ENA 

 output lpi_fw;                         //  LPI transmit and receive functions control
 input  [15:0] wake_error_counter;      //  A counter that is incremented each time that the LPI receive state diagram enters the RX_WTF
 output wake_error_counter_rd;          //  Wake error counter has been read
 input  tx_lpi_indication;              //  Tx LPI indication A Boolean variable indicating the current state of the transmit LPI function. 
 input  rx_lpi_indication;              //  Rx LPI indication. A Boolean variable indicating the current state of the receive LPI function. 

`endif

`ifdef MTIP_DIR_CONFIG

 input   sw_reset_dir;           //  Software PCS reset - sets the bit 15 of the PCS CONTROL 1 register

`endif

input   reg_rd;                 //  Register Read Strobe
input   reg_wr;                 //  Register Write Strobe
input   [15:0] reg_addr;        //  Register Address
input   [15:0] reg_din;         //  Write Data from Host Bus
output  [15:0] reg_dout;        //  Read Data to Host Bus
output  reg_busy;               //  Acknowledgement for read/write operation
output  sw_reset;               //  Software Reset
output  loopback_ena;           //  Loopback Enable

`ifdef MTIPPCS40_VENDORCFGREGS
 
 output  [15:0] vl_intvl;        //  marker distance shortened (1) or standard (0).
 output  [3:0] tx_lane_thresh;   //  4 bit per lane tx decoupling buffer level threshold (5..7 depending on refclk)
 wire    [15:0] vl_intvl; 
 wire    [3:0] tx_lane_thresh; 

`endif

`ifdef MTIPPCS82_EEE_ENA 

 reg    lpi_fw;
 wire   wake_error_counter_rd;

`endif

wire    ber_count_read; 
wire    err_block_cnt_rd; 
wire    tx_test_mode; 
wire    rx_test_mode; 
wire    pat_err_cnt_rd; 
reg     [15:0] reg_dout; 
reg     reg_busy; 
wire    sw_reset; 
wire    loopback_ena; 

`ifdef MTIPPCS82_EEE_ENA

 wire   [15:0] eee_control_capab;
 reg    [15:0] wake_error_counter_r;                
 reg    [15:0] wake_error_counter_r2;
 reg    [15:0] wake_error_counter_r3;
 wire   clear_wake_error_counter_r3;
 wire   s_clear_wake_error_counter_r3;

`endif

parameter STM_TYPE_IDLE         = 3'd 0;
parameter STM_TYPE_READ         = 3'd 1;
parameter STM_TYPE_WRITE        = 3'd 2;
parameter STM_TYPE_WAIT_CYCLE   = 3'd 3;
parameter STM_TYPE_WAIT1        = 3'd 4;
parameter STM_TYPE_WAIT2        = 3'd 5;

reg     [2:0] state; 
reg     [2:0] nextstate; 
wire    [11:0] reg_sel; 
wire    [11:0] reg_sel_v; //  merged reg_sel_vendor for read mux
reg     [11:0] reg_sel_reg; 
reg     [15:0] reg_din_reg; //  Write Data from Host Bus
wire    reg_sel_vendor; //  vendor specific address space
reg     reg_sel_vendor_reg; 
reg     reg_rd_int; 
reg     reg_wr_int; 
//  CONTROL 1 Register
//  ------------------
wire    [15:0] control1; 
reg     control1_14; 
reg     control1_15; 
wire    control1_15_reg2; 
wire    control1_15_reg4; 
wire    [4:0] speed_select; 
wire    speed_select1; 
wire    power_dwn; 
wire    sw_reset_int; 
//  STATUS 1 Register
//  -----------------
wire    [15:0] status1; 
reg     status1_2; //  link status, LL

`ifdef MTIPPCS82_EEE_ENA

 reg     status1_11;            //11: Tx LPI received. A Boolean variable indicating the current state of the transmit LPI function. 
                                // This flag is set to true when the LPI transmit state diagram is in any state other than TX_ACTIVE(LH).


 reg     status1_10;            //10: Rx LPI received. A Boolean variable indicating the current state of the receive LPI function. 
                                // This flag is set to true when the LPI receive state diagram is in any state other than RX_ACTIVE (LH).

 wire   status1_9;              // tx_lpi_indication:      
                                //  status 1[9]:  Tx LPI indication A Boolean variable indicating the current state of the transmit LPI function. 
                                //  This flag is set to true when the LPI transmit state diagram is in any state other than TX_ACTIVE.

 wire   status1_8;              //rx_lpi_indication:      
                                //  status 1[8]:  Rx LPI indication. A Boolean variable indicating the current state of the receive LPI function. 
                                // This flag is set to true when the LPI receive state diagram is in any state other than RX_ACTIVE.
                                
`endif

wire    c_rx_err; 
wire    c_tx_err; 
wire    low_pwr_ability; 
wire    link_status_s; 
//  DEVICE ID Register
//  ------------------
wire    [31:0] phy_identifier_w; 
//  SPEED ABILITY Register
//  ----------------------
wire    [15:0] speed_ability; 
//  DEVICES IN PACKAGE Register
//  ---------------------------
wire    [31:0] devices_w; 
//  CONTROL 2 Register
//  ------------------
wire    [15:0] control2; 
//  STATUS 2 Register
//  -----------------
wire    [15:0] status2; 
reg     status2_10; 
reg     status2_11; 
wire    capable_100gbase_r; 
wire    capable_40gbase_r; 
wire    capable_10gbase_t; 
wire    capable_10gbase_w; 
wire    capable_10gbase_x; 
wire    capable_10gbase_r; 
//  PACKAGE ID Register
//  -------------------
wire    [31:0] pack_identifier_w; 
//  10/40G/100GBASE-R STATUS 1 Register
//  -----------------------------------
wire    [15:0] status1_100gbase_r; 
wire    prbs9_ability; 
wire    prbs31_ability; 
wire    block_lock_s; 
wire    hi_ber_s; 
//  10/40G/100GBASE-R STATUS 2 Register
//  -----------------------------------
reg     [15:0] status2_100gbase_r; 
reg     [21:0] ber_count_reg1; 
reg     [21:0] ber_count_reg2; 
reg     [21:0] err_block_cnt_reg1; 
reg     [21:0] err_block_cnt_reg2; 
wire    clear_status2_100gbase_r; 
wire    s_clear_status2_100gbase_r; 
//  10/40G/100GBASE-R SEED A Register
//  ---------------------------------
//  10GBASE-R SEED B Register
//  -------------------------
//  10/40G/100GBASE-R TEST CONTROL Register
//  ---------------------------------------
wire    [15:0] test_control_100gbase_r; 
reg     test_control_100gbase_r_3; 
reg     test_control_100gbase_r_2; 
wire    prbs9_tx_enable; 
wire    prbs31_rx_enable; 
wire    prbs31_tx_enable; 
//  10/40G/100GBASE-R TEST ERROR COUNTER Register
//  ---------------------------------------------
reg     [15:0] test_err_cnt_100gbase_r; 
reg     [15:0] pat_err_cnt_reg1; 
reg     [15:0] pat_err_cnt_reg2; 
wire    clear_test_err_cnt_100gbase_r; 
wire    s_clear_test_err_cnt_100gbase_r; 
//  BER HIGH ORDER COUNTER Register
//  -------------------------------
wire    [15:0] ber_high_order_cnt; 
reg     [15:0] ber_high_order_cnt_l; 
//  ERRORED BLOCKS HIGH ORDER COUNTER Register
//  ------------------------------------------
wire    [15:0] err_blk_high_order_cnt; 
reg     [15:0] err_blk_high_order_cnt_l; 
//  MULTI-LANE ALIGNMENT STATUS 1 - 4 Register
//  ------------------------------------------
wire    [15:0] status1_ml_align; 
wire    [15:0] status2_ml_align; 
wire    [15:0] status3_ml_align; 
wire    [15:0] status4_ml_align; 
reg     [3:0] block_lock_3_0_reg1; 
reg     [3:0] block_lock_3_0_reg2; 
reg     align_lock_reg1; 
reg     align_lock_reg2; 
reg     [3:0] align_lock_3_0_reg1; 
reg     [3:0] align_lock_3_0_reg2; 
//  BIP ERROR COUNTER LANE 0 Register
//  ---------------------------------
wire    [15:0] bip_cnt_0; 
wire    [15:0] bip_cnt_1; 
wire    [15:0] bip_cnt_2; 
wire    [15:0] bip_cnt_3; 
//  PCS LANE MAPPING Registers
//  --------------------------
wire    [7:0] lane_map_s; 
wire    [1:0] lane_map_0; 
wire    [1:0] lane_map_1; 
wire    [1:0] lane_map_2; 
wire    [1:0] lane_map_3; 
//  SCRATCH Register
//  ----------------
reg     [15:0] scratch_reg; 
//  CORE DESIGN REVISION Register
//  -----------------------------
wire    [15:0] core_rev; 
//  Additional Vendor registers for global configuration options
//  -----------------------------
`ifdef MTIPPCS40_VENDORCFGREGS
reg     [15:0] vl_intvl_reg; 
reg     [3:0] tx_lane_thresh_reg; 
`endif

// remap 16-bit register space into a 12-bit space
// 0..0x07ff direct.
// 0x800  .. 0x7fff => always to 0x07ff unused register to ensure returning 0
// 0x8000 .. 0xffff => vendor space.

assign reg_sel = reg_addr[14:11] == 4'b 0000 ? {1'b 0, reg_addr[10:0]} : 12'h 7FF; //  ensure reserved return 0 always
assign reg_sel_vendor = reg_addr[15]; 

//  CONTROL 1 Register (0)
//  ----------------------
assign speed_select = 5'b 10011; //  40 Gb/s
assign speed_select1 = 1'b 1; //  10/40/100 Gb/s
assign power_dwn = 1'b 0; 
assign control1 = {control1_15, control1_14, speed_select1, 1'b 0, power_dwn, 4'b 0000, speed_select, 2'b 00}; 

//  Sofware reset domain crossing reg_clk -> rx_clk -> reg_clk to stretch sw-reset
// 

mtip_xsync #(1) U_SYCTL115X (
          .data_in(control1_15),
          .reset(reset_rx_clk),
          .clk(rx_clk),
          .data_s(control1_15_reg2));

mtip_xsync #(1) U_SYCTL115R (
          .data_in(control1_15_reg2),
          .reset(reset_reg_clk),
          .clk(reg_clk),
          .data_s(control1_15_reg4));

always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_1
   if (reset_reg_clk == 1'b 1)
      begin
      control1_14 <= 1'b 0;	
      control1_15 <= 1'b 0;	
      end
   else
      begin

        //   Self-clearing software reset
        // 

      `ifdef MTIP_DIR_CONFIG
      if (sw_reset_dir==1'b 1)
         begin
         control1_15 <= 1'b 1;	
         end
      else
      `endif
      if (control1_15_reg4 == 1'b 1)
         begin
         control1_15 <= 1'b 0;	
         end
      else if (reg_wr_int == 1'b 1 & reg_sel_reg == 12'h 000 & reg_sel_vendor_reg == 1'b 0 )
         begin
         control1_15 <= reg_din_reg[15];	
         end

        //  Loopback enable
        // 

      if (reg_wr_int == 1'b 1 & reg_sel_reg == 12'h 000 & reg_sel_vendor_reg == 1'b 0)
         begin
         control1_14 <= reg_din_reg[14];	
         end

      end
   end

assign sw_reset     = control1[15]; 
assign sw_reset_int = control1[15]; 

mtip_xsync #(1) U_SYCLP (

          .data_in(control1[14]),
          .reset(reset_rx_clk),
          .clk(rx_clk),
          .data_s(loopback_ena));

//  STATUS 1 Register (1)
//  ---------------------

assign low_pwr_ability = 1'b 0;

`ifdef MTIPPCS82_EEE_ENA

 assign status1[15:12] = 4'h 0; //  reserved
 assign status1[11]    = status1_11;
 assign status1[10]    = status1_10;
 assign status1[9]     = status1_9;
 assign status1[8]     = status1_8;

`else

 assign status1[15:8] = 8'h 00; //  reserved

`endif

//  IEEE 802.3: Bit 3.1.7 is read as a one when either of the fault bits
//  (3.8.11, 3.8.10) located in register 3.8 are read as a one.
//  Bit 3.1.7 is cleared when the fault bits (3.8.11, 3.8.10) are cleared.
// 
assign status1[7] = status2[11] | status2[10]; 
assign status1[6:3] = 4'h 0; //  reserved
assign status1[2] = status1_2; //  link status, LL
assign status1[1] = low_pwr_ability; 
assign status1[0] = 1'b 0; //  reserved

//  Latch low for link status
// 
mtip_xsync #(1) U_SYLINK (
          .data_in(link_status),
          .reset(reset_reg_clk),
          .clk(reg_clk),
          .data_s(link_status_s));

always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_2
   if (reset_reg_clk == 1'b 1)
      begin
      status1_2 <= 1'b 0;	
      end
   else
      begin
      if (reg_rd_int == 1'b 1 & reg_sel_reg == 12'h 001 & reg_sel_vendor_reg == 1'b 0)
         begin
         status1_2 <= link_status_s;	//  reset on read
         end
      else if (link_status_s == 1'b 0 )
         begin
         status1_2 <= 1'b 0;	
         end
      end
   end
   

`ifdef MTIPPCS82_EEE_ENA
 
 //11: Tx LPI received
 //A Boolean variable indicating the current state of the transmit LPI function. This flag is set to true when the LPI transmit state diagram is in any state other than TX_ACTIVE(LH).
 ///10: Rx LPI received
 //A Boolean variable indicating the current state of the receive LPI function. This flag is set to true when the LPI receive state diagram is in any state other than RX_ACTIVE (LH).

 //  status 1[9]:  Tx LPI indication A Boolean variable indicating the current state of the transmit LPI function. 
 //  This flag is set to true when the LPI transmit state diagram is in any state other than TX_ACTIVE.

 //  status 1[8]:  Rx LPI indication. A Boolean variable indicating the current state of the receive LPI function. 
 // This flag is set to true when the LPI receive state diagram is in any state other than RX_ACTIVE.

 mtip_xsync #(2) U_SYLPI_IND (
 
          .data_in({tx_lpi_indication, rx_lpi_indication}),
          .reset(reset_reg_clk),
          .clk(reg_clk),
          .data_s({status1_9, status1_8}));

 always @(posedge reset_reg_clk or posedge reg_clk)
   begin
   if (reset_reg_clk == 1'b 1)
      begin
      status1_10 <= 1'b 0;	
      status1_11 <= 1'b 0;
      end
   else
      begin
      if (reg_rd_int == 1'b 1 & reg_sel_reg == 12'h 001 & reg_sel_vendor_reg == 1'b 0)
         begin	
         status1_10 <= status1_8;//  reset on read	
         status1_11 <= status1_9;
         end
      else 
         begin
         if (status1_8 == 1'b 1)
            begin
            status1_10 <= 1'b 1;	
            end
         if (status1_9 == 1'b 1)
            begin
            status1_11 <= 1'b 1;	
            end                        
         end
      end
   end

`endif

//  DEVICE ID Register (2, 3)
//  -------------------------
assign phy_identifier_w[31:4] = PHY_IDENTIFIER[31:4]; 
assign phy_identifier_w[3:0] = CHNL_NO; 

//  SPEED ABILITY Register (4)
//  --------------------------
assign speed_ability = 16'h 0004; //  40G capable

//  DEVICES IN PACKAGE Register (5, 6)
//  ----------------------------------
assign devices_w = {16'h 0000, 16'h 0008}; //  PCS present in package

//  CONTROL 2 Register (7)
//  ----------------------
assign control2 = 16'h 0004; //  40 Gb/s

//  STATUS 2 Register (8)
//  ---------------------

redge_ckxing U_RX_ERR (
          .reset(reset_rx_clk),
          .clk(rx_clk),
          .sig(rx_err),          //  input pulse/rising
          .reset_clk_o(reset_reg_clk),
          .clk_o(reg_clk),
          .sig_o(c_rx_err));

redge_ckxing U_TX_ERR (
          .reset(reset_tx_clk),
          .clk(tx_clk),
          .sig(tx_err),          //  input pulse/rising
          .reset_clk_o(reset_reg_clk),
          .clk_o(reg_clk),
          .sig_o(c_tx_err));    //  fault detected on transmit path in reg clock domain

assign capable_100gbase_r = 1'b 0; //  fault detected on receive path in reg clock domain
assign capable_40gbase_r = 1'b 1; 
assign capable_10gbase_t = 1'b 0; 
assign capable_10gbase_w = 1'b 0; 
assign capable_10gbase_x = 1'b 0; 
assign capable_10gbase_r = 1'b 0; 
assign status2[15:12] = 4'b 1000; //  device responding
assign status2[11] = status2_11; 
assign status2[10] = status2_10; 
assign status2[9:0] = {4'b 0000, capable_100gbase_r, capable_40gbase_r, capable_10gbase_t, 
                                 capable_10gbase_w, capable_10gbase_x, capable_10gbase_r}; 

//  Latch high for transmit fault and receive fault
// 
always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_3
   if (reset_reg_clk == 1'b 1)
      begin
      status2_10 <= 1'b 0;	
      status2_11 <= 1'b 0;	
      end
   else
      begin
      if (reg_rd_int == 1'b 1 & reg_sel_reg == 12'h 008 & reg_sel_vendor_reg == 1'b 0 | sw_reset_int == 1'b 1)
         begin
         status2_10 <= 1'b 0;	//  reset on read
         status2_11 <= 1'b 0;	//  reset on read
         end
      else
         begin
         if (c_rx_err == 1'b 1)
            begin
            status2_10 <= 1'b 1;	
            end
         if (c_tx_err == 1'b 1)
            begin
            status2_11 <= 1'b 1;	
            end
         end
      end
   end

//  PACKAGE ID Register (14, 15)
//  ----------------------------
assign pack_identifier_w = PACK_IDENTIFIER; 

//  10/40G/100GBASE-R STATUS 1 Register (32)
//  ----------------------------------------
mtip_xsync #(1) U_SYBLOCK (
          .data_in(block_lock),
          .reset(reset_reg_clk),
          .clk(reg_clk),
          .data_s(block_lock_s));

mtip_xsync #(1) U_SYBER (
          .data_in(hi_ber),
          .reset(reset_reg_clk),
          .clk(reg_clk),
          .data_s(hi_ber_s));

assign prbs9_ability = 1'b 0; 
assign prbs31_ability = 1'b 0; 
assign status1_100gbase_r[15:13] = 3'b 000; //  reserved
assign status1_100gbase_r[12] = link_status_s; 
assign status1_100gbase_r[11:2] = {8'h 00, prbs9_ability, prbs31_ability}; 
assign status1_100gbase_r[1] = hi_ber_s; 
assign status1_100gbase_r[0] = block_lock_s;

`ifdef MTIPPCS82_EEE_ENA

 always @(posedge reset_reg_clk or posedge reg_clk)
   begin
   if (reset_reg_clk == 1'b 1)
      begin
      lpi_fw <= 1'b 0;		
      end
   else
      begin
      if (reg_wr_int == 1'b 1 & reg_sel_reg == 12'h 014 & reg_sel_vendor_reg == 1'b 0)
         begin
         lpi_fw <=  reg_din_reg[0];
         end
      end
   end

 assign eee_control_capab[0] = lpi_fw;
 assign eee_control_capab[7:1] = 7'd0; 
 assign eee_control_capab[8] = 1'b1;     // Fast Wake up support 40G
 assign eee_control_capab[9] = 1'b1;     // Deep sleep support 40G
 assign eee_control_capab[15:10] = 6'd0;

 always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_39
   if (reset_reg_clk == 1'b 1)
      begin
      wake_error_counter_r <= {16{1'b 0}};	
      wake_error_counter_r2 <= {16{1'b 0}};	
      wake_error_counter_r3 <= {16{1'b 0}};	
      end
   else
      begin
      wake_error_counter_r <= wake_error_counter;	
      wake_error_counter_r2 <= wake_error_counter_r;	
      wake_error_counter_r3 <= wake_error_counter_r2;	
      end
   end

 assign clear_wake_error_counter_r3 = reg_rd_int == 1'b 1 & reg_sel_reg == 12'h 016 & reg_sel_vendor_reg == 1'b 0 |
                                      sw_reset_int == 1'b 1 ? 1'b 1 : 1'b 0; 

 //  clear_test_err_cnt_100gbase_r domain crossing
 //  ---------------------------------------------
 
 redge_ckxing U_CLR_WAKE_ERR_CNT (
 
          .reset(reset_reg_clk),
          .clk(reg_clk),
          .sig(clear_wake_error_counter_r3),
          .reset_clk_o(reset_rx_clk),
          .clk_o(rx_clk),
          .sig_o(s_clear_wake_error_counter_r3));

 assign wake_error_counter_rd = s_clear_wake_error_counter_r3; 

`endif

//  10/40G/100GBASE-R STATUS 2 Register (33)
//  ----------------------------------------
always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_4
   if (reset_reg_clk == 1'b 1)
      begin
      ber_count_reg1 <= {22{1'b 0}};	
      ber_count_reg2 <= {22{1'b 0}};	
      err_block_cnt_reg1 <= {22{1'b 0}};	
      err_block_cnt_reg2 <= {22{1'b 0}};	
      status2_100gbase_r[15:0] <= {16{1'b 0}};	
      end
   else
      begin
      ber_count_reg1 <= ber_count;	
      ber_count_reg2 <= ber_count_reg1;	
      err_block_cnt_reg1 <= err_block_cnt;	
      err_block_cnt_reg2 <= err_block_cnt_reg1;	
      status2_100gbase_r[13:0] <= {ber_count_reg2[5:0], err_block_cnt_reg2[7:0]};	
      if (clear_status2_100gbase_r == 1'b 1)
         begin
         status2_100gbase_r[15] <= block_lock_s;	//  reset on read
         status2_100gbase_r[14] <= hi_ber_s;	
         end
      else
         begin

                //  Latch low for block lock
                // 

         if (block_lock_s == 1'b 0)
            begin
            status2_100gbase_r[15] <= 1'b 0;	
            end

                //  Latch high for high BER
                // 
         if (hi_ber_s == 1'b 1)
            begin
            status2_100gbase_r[14] <= 1'b 1;	
            end

         end
      end
   end

//  status2_100gbase_r read done
// 
assign clear_status2_100gbase_r = reg_rd_int == 1'b 1 & reg_sel_reg == 12'h 021 & reg_sel_vendor_reg == 1'b 0 | 
                                  sw_reset_int == 1'b 1 ? 1'b 1 : 1'b 0; 

//  clear_status2_100gbase_r domain crossing
// 
redge_ckxing U_CLR_STAT2 (
          .reset(reset_reg_clk),
          .clk(reg_clk),
          .sig(clear_status2_100gbase_r),
          .reset_clk_o(reset_rx_clk),
          .clk_o(rx_clk),
          .sig_o(s_clear_status2_100gbase_r));

assign ber_count_read = s_clear_status2_100gbase_r; 
assign err_block_cnt_rd = s_clear_status2_100gbase_r; 

//  10/40G/100GBASE-R TEST CONTROL Register (42)
//  --------------------------------------------
assign prbs9_tx_enable = 1'b 0; 
assign prbs31_rx_enable = 1'b 0; 
assign prbs31_tx_enable = 1'b 0; 
assign test_control_100gbase_r[15:7] = {9{1'b 0}}; //  reserved
assign test_control_100gbase_r[6:4] = {prbs9_tx_enable, prbs31_rx_enable, prbs31_tx_enable}; 
assign test_control_100gbase_r[3] = test_control_100gbase_r_3; 
assign test_control_100gbase_r[2] = test_control_100gbase_r_2; 
assign test_control_100gbase_r[1:0] = 2'b 00; 
always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_5
   if (reset_reg_clk == 1'b 1)
      begin
      test_control_100gbase_r_3 <= 1'b 0;	
      test_control_100gbase_r_2 <= 1'b 0;	
      end
   else
      begin
      if (reg_wr_int == 1'b 1 & reg_sel_reg == 12'h 02A & reg_sel_vendor_reg == 1'b 0)
         begin
         test_control_100gbase_r_3 <= reg_din_reg[3];	
         test_control_100gbase_r_2 <= reg_din_reg[2];	
         end
      end
   end


mtip_xsync #(1) U_STSTX (

          .data_in(test_control_100gbase_r[3]),
          .reset(reset_tx_clk),
          .clk(tx_clk),
          .data_s(tx_test_mode));
          
mtip_xsync #(1) U_STSRX (

          .data_in(test_control_100gbase_r[2]),
          .reset(reset_rx_clk),
          .clk(rx_clk),
          .data_s(rx_test_mode));

//  10/40G/100GBASE-R TEST ERROR COUNTER Register (43)
//  --------------------------------------------------
always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_6
   if (reset_reg_clk == 1'b 1)
      begin
      pat_err_cnt_reg1 <= {16{1'b 0}};	
      pat_err_cnt_reg2 <= {16{1'b 0}};	
      test_err_cnt_100gbase_r <= {16{1'b 0}};	
      end
   else
      begin
      pat_err_cnt_reg1 <= pat_err_cnt;	
      pat_err_cnt_reg2 <= pat_err_cnt_reg1;	
      test_err_cnt_100gbase_r <= pat_err_cnt_reg2;	
      end
   end

//  test_err_cnt_100gbase_r read done
// 
assign clear_test_err_cnt_100gbase_r = reg_rd_int == 1'b 1 & reg_sel_reg == 12'h 02B & reg_sel_vendor_reg == 1'b 0 |
                                       sw_reset_int == 1'b 1 ? 1'b 1 : 1'b 0; 

//  clear_test_err_cnt_100gbase_r domain crossing
// 
redge_ckxing U_CLR_TEST_ERR_CNT (
          .reset(reset_reg_clk),
          .clk(reg_clk),
          .sig(clear_test_err_cnt_100gbase_r),
          .reset_clk_o(reset_rx_clk),
          .clk_o(rx_clk),
          .sig_o(s_clear_test_err_cnt_100gbase_r));

assign pat_err_cnt_rd = s_clear_test_err_cnt_100gbase_r; 

//  BER HIGH ORDER COUNTER Register (44)
//  ------------------------------------
assign ber_high_order_cnt = ber_count_reg2[21:6]; 

//  ERRORED BLOCKS HIGH ORDER COUNTER Register (45)
//  -----------------------------------------------
assign err_blk_high_order_cnt[15] = 1'b 1; //  high order counter present
assign err_blk_high_order_cnt[14] = 1'b 0; //  reserved
assign err_blk_high_order_cnt[13:0] = err_block_cnt_reg2[21:8]; 

always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_7
   if (reset_reg_clk == 1'b 1)
      begin
      ber_high_order_cnt_l <= {16{1'b 0}};	
      err_blk_high_order_cnt_l <= {16{1'b 0}};	
      end
   else
      begin
      if (clear_status2_100gbase_r == 1'b 1)
         begin
        //  latch high order counters when reading status2_100gbase_r
         ber_high_order_cnt_l <= ber_high_order_cnt;	
         err_blk_high_order_cnt_l <= err_blk_high_order_cnt;	
         end
      end
   end

//  MULTI-LANE ALIGNMENT STATUS 1 - 4 Register (50 - 53)
//  ----------------------------------------------------
always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_8
   if (reset_reg_clk == 1'b 1)
      begin
      block_lock_3_0_reg1 <= {4{1'b 0}};	
      block_lock_3_0_reg2 <= {4{1'b 0}};	
      align_lock_reg1 <= 1'b 0;	
      align_lock_reg2 <= 1'b 0;	
      align_lock_3_0_reg1 <= {4{1'b 0}};	
      align_lock_3_0_reg2 <= {4{1'b 0}};	
      end
   else
      begin
      block_lock_3_0_reg1 <= block_lock_3_0;	
      block_lock_3_0_reg2 <= block_lock_3_0_reg1;	
      align_lock_reg1 <= align_lock;	
      align_lock_reg2 <= align_lock_reg1;	
      align_lock_3_0_reg1 <= align_lock_3_0;	
      align_lock_3_0_reg2 <= align_lock_3_0_reg1;	
      end
   end

assign status1_ml_align[15:13] = 3'b 000;       //  reserved
assign status1_ml_align[12] = align_lock_reg2; 
assign status1_ml_align[11:8] = 4'h 0;          //  reserved
assign status1_ml_align[7:4] = 4'h 0;           //  block lock 7..4
assign status1_ml_align[3:0] = block_lock_3_0_reg2; 
assign status2_ml_align[15:12] = 4'h 0;         //  reserved
assign status2_ml_align[11:0] = 12'h 000;       //  block lock 19..8
assign status3_ml_align[15:8] = 8'h 00;         //  reserved
assign status3_ml_align[7:4] = 4'h 0;           //  aligned lanes 7..4
assign status3_ml_align[3:0] = align_lock_3_0_reg2; 
assign status4_ml_align[15:12] = 4'h 0;         //  reserved
assign status4_ml_align[11:0] = 12'h 000;       //  aligned lanes 19..8

//  BIP ERROR COUNTER LANE 0 Register (90)

bip_error_count_top_40g U_BIP_CNT_TOP (
          .reset_rx_clk(reset_rx_clk),
          .reset_reg_clk(reset_reg_clk),
          .rx_clk(rx_clk),
          .reg_clk(reg_clk),
          .sw_reset(sw_reset_int),
          .bip8_stat_0(bip8_stat_0),
          .bip8_stat_1(bip8_stat_1),
          .bip8_stat_2(bip8_stat_2),
          .bip8_stat_3(bip8_stat_3),
          .reg_rd(reg_rd_int),
          .reg_sel(reg_sel_reg),
          .reg_sel_vendor(reg_sel_vendor_reg),
          .cnt0(bip_cnt_0),
          .cnt1(bip_cnt_1),
          .cnt2(bip_cnt_2),
          .cnt3(bip_cnt_3));

mtip_xsync #(8) U_SYLMAP (
          .data_in(lane_map),
          .reset(reset_reg_clk),
          .clk(reg_clk),
          .data_s(lane_map_s));

assign lane_map_0 = lane_map_s[1:0]; 
assign lane_map_1 = lane_map_s[3:2]; 
assign lane_map_2 = lane_map_s[5:4]; 
assign lane_map_3 = lane_map_s[7:6]; 

//  Vendor Specific Registers
//  -------------------------

//  SCRATCH Register - Vendor 0 (32768+0)
//  ----------------
always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_9
   if (reset_reg_clk == 1'b 1)
      begin
      scratch_reg <= {16{1'b 0}};	
      end
   else
      begin
      if (reg_wr_int == 1'b 1 & reg_sel_reg == 12'h 000 & reg_sel_vendor_reg == 1'b 1)
         begin
         scratch_reg <= reg_din_reg;	
         end
      end
   end

//  CORE DESIGN REVISION Register - Vendor 1 (32768+1)
//  -----------------------------
assign core_rev = DEV_VERSION; 

`ifdef MTIPPCS40_VENDORCFGREGS

//  Shorter Marker distance - Vendor 2 (32768+2)
//  -----------------------
always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_10
   if (reset_reg_clk == 1'b 1)
      begin
      vl_intvl_reg <= 16'd 0;	
      end
   else
      begin
      if (reg_wr_int == 1'b 1 & reg_sel_reg == 12'h 002 & reg_sel_vendor_reg == 1'b 1)
         begin
         vl_intvl_reg <= reg_din_reg[15:0];	
         end
      end
   end

assign vl_intvl = vl_intvl_reg; 

//  TX Lane Threshold - Vendor 3 (32768+3)
//  ----------------
always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_11
   if (reset_reg_clk == 1'b 1)
      begin
      tx_lane_thresh_reg <= 4'h 6;	
      end
   else
      begin
      if (reg_wr_int == 1'b 1 & reg_sel_reg == 12'h 003 & reg_sel_vendor_reg == 1'b 1)
         begin
         tx_lane_thresh_reg <= reg_din_reg[3:0];	
         end
      end
   end

assign tx_lane_thresh = tx_lane_thresh_reg; 

`endif

//  Read MUX
//  --------

assign reg_sel_v = {reg_sel_vendor, reg_sel[10:0]}; //  merge vendor into bit11 as its unused to simplify the mux below.

always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_12
   if (reset_reg_clk == 1'b 1)
      begin
      reg_dout <= {16{1'b 0}};	
      end
   else
      begin
      if (reg_rd == 1'b 1)
         begin
         case (reg_sel_v)
         12'h 000:
            begin
            reg_dout <= control1;	
            end
         12'h 001:
            begin
            reg_dout <= status1;	
            end
         12'h 002:
            begin
            reg_dout <= phy_identifier_w[15:0];	
            end
         12'h 003:
            begin
            reg_dout <= phy_identifier_w[31:16];	
            end
         12'h 004:
            begin
            reg_dout <= speed_ability;	
            end
         12'h 005:
            begin
            reg_dout <= devices_w[15:0];	
            end
         12'h 006:
            begin
            reg_dout <= devices_w[31:16];	
            end
         12'h 007:
            begin
            reg_dout <= control2;	
            end
         12'h 008:
            begin
            reg_dout <= status2;	
            end
         12'h 00E:
            begin
            reg_dout <= pack_identifier_w[15:0];	
            end
         12'h 00F:
            begin
            reg_dout <= pack_identifier_w[31:16];
            
            end

      `ifdef MTIPPCS82_EEE_ENA

         12'h 014:
            begin
            reg_dout <= eee_control_capab;	
            end

         12'h 016:
            begin
            reg_dout <= wake_error_counter_r3;	
            end
        
      `endif   
         
         12'h 020:
            begin
            reg_dout <= status1_100gbase_r;	
            end
         12'h 021:
            begin
            reg_dout <= status2_100gbase_r;	
            end
         12'h 022:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 023:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 024:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 025:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 026:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 027:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 028:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 029:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 02A:
            begin
            reg_dout <= test_control_100gbase_r;	
            end
         12'h 02B:
            begin
            reg_dout <= test_err_cnt_100gbase_r;	
            end
         12'h 02C:
            begin
            reg_dout <= ber_high_order_cnt_l;	
            end
         12'h 02D:
            begin
            reg_dout <= err_blk_high_order_cnt_l;	
            end
         12'h 032:
            begin
            reg_dout <= status1_ml_align;	
            end
         12'h 033:
            begin
            reg_dout <= status2_ml_align;	
            end
         12'h 034:
            begin
            reg_dout <= status3_ml_align;	
            end
         12'h 035:
            begin
            reg_dout <= status4_ml_align;	
            end
         12'h 0C8:
            begin
            reg_dout <= bip_cnt_0;	
            end
         12'h 0C9:
            begin
            reg_dout <= bip_cnt_1;	
            end
         12'h 0CA:
            begin
            reg_dout <= bip_cnt_2;	
            end
         12'h 0CB:
            begin
            reg_dout <= bip_cnt_3;	
            end
         12'h 0CC:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 0CD:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 0CE:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 0CF:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 0D0:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 0D1:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 0D2:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 0D3:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 0D4:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 0D5:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 0D6:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 0D7:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 0D8:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 0D9:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 0DA:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 0DB:
            begin
            reg_dout <= 16'b 0000000000000000;	
            end
         12'h 190:
            begin
            reg_dout <= {14'b 00000000000000, lane_map_0};	
            end
         12'h 191:
            begin
            reg_dout <= {14'b 00000000000000, lane_map_1};	
            end
         12'h 192:
            begin
            reg_dout <= {14'b 00000000000000, lane_map_2};	
            end
         12'h 193:
            begin
            reg_dout <= {14'b 00000000000000, lane_map_3};	
//  vendor specific registers (bit11=1)
            end
         12'h 800:
            begin
            reg_dout <= scratch_reg;	
            end
         12'h 801:
            begin
            reg_dout <= core_rev;	
            end

        `ifdef MTIPPCS40_VENDORCFGREGS

         12'h 802:
            begin
            reg_dout <= vl_intvl_reg;	
            end
         12'h 803:
            begin
            reg_dout <= {12'h 000, tx_lane_thresh_reg};	
            end

        `endif

         default:
            begin
            reg_dout <= {16{1'b 0}};	
            end
         endcase
         end
      else
         begin
         reg_dout <= {16{1'b 0}};	
         end
      end
   end

//  STM
//  ---
always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_13
   if (reset_reg_clk == 1'b 1)
      begin
      state <= STM_TYPE_IDLE;	
      end
   else
      begin
      state <= nextstate;	
      end
   end

always @(state or reg_rd or reg_wr)
   begin : process_14
   case (state)
   STM_TYPE_IDLE:
      begin
        //  Write Accesses
        // 
      if (reg_wr == 1'b 1)
         begin
         nextstate = STM_TYPE_WRITE;	
        //  Read Accesses
        // 
         end
      else if (reg_rd == 1'b 1 )
         begin
         nextstate = STM_TYPE_READ;	
         end
      else
         begin
         nextstate = STM_TYPE_IDLE;	
         end
      end
   STM_TYPE_READ:
      begin
      nextstate = STM_TYPE_WAIT_CYCLE;	
      end
   STM_TYPE_WRITE:
      begin
      nextstate = STM_TYPE_WAIT_CYCLE;	
      end
   STM_TYPE_WAIT_CYCLE:
      begin
        //  acknowledge
      nextstate = STM_TYPE_WAIT1;	
      end
   STM_TYPE_WAIT1:
      begin
        //  extra latency to allow input regs
      nextstate = STM_TYPE_WAIT2;	
      end
   STM_TYPE_WAIT2:
      begin
        //  extra latency to allow output regs
      nextstate = STM_TYPE_IDLE;	
      end
   default:
      begin
      nextstate = STM_TYPE_IDLE;	
      end
   endcase
   end

//  Registers Control
//  -----------------
always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_15
   if (reset_reg_clk == 1'b 1)
      begin
      reg_sel_reg <= {12{1'b 0}};	
      reg_sel_vendor_reg <= 1'b 0;	
      reg_din_reg <= {16{1'b 0}};	
      end
   else
      begin
      reg_sel_reg <= reg_sel;	//  bit11 is used as vendor selector, as its unused.
      reg_sel_vendor_reg <= reg_sel_vendor;	
      reg_din_reg <= reg_din;	
      end
   end

always @(posedge reset_reg_clk or posedge reg_clk)
   begin : process_16
   if (reset_reg_clk == 1'b 1)
      begin
      reg_rd_int <= 1'b 0;	
      reg_wr_int <= 1'b 0;	
      reg_busy <= 1'b 1;	
      end
   else
      begin
//  make internal read single cycle pulse
      if (nextstate == STM_TYPE_READ)
         begin
         reg_rd_int <= 1'b 1;	
         end
      else
         begin
         reg_rd_int <= 1'b 0;	
         end
      if (nextstate == STM_TYPE_WRITE)
         begin
         reg_wr_int <= 1'b 1;	
         end
      else
         begin
         reg_wr_int <= 1'b 0;	
         end
//  cycle handshake
      if (nextstate == STM_TYPE_WAIT_CYCLE)
         begin
         reg_busy <= 1'b 0;	
         end
      else
         begin
         reg_busy <= 1'b 1;	
         end
      end
   end


endmodule // module register_map_pcs_40g

